﻿using System;
using System.Collections.Generic;
using System.Text;
using Encog.ML;
using Encog.ML.Train;
using Encog.ML.Train.Strategy.End;
using Encog.Neural.Networks;

namespace PW.Mini.SlepowronskiJ.Siec.Algorytmy
{
    [Serializable]
    public class WzrostBleduWalidacyjnegoStrategia : WzrostBleduWalidacyjnego, IEndTrainingStrategy    
    {
        /// <summary>
        /// Algorytm uczacy uzywajacy tej strategii
        /// </summary>
        ///
        [NonSerialized]
        private IMLTrain train;

        /// <summary>
        /// Sieć neuronowa
        /// </summary>
        ///
        private BasicNetwork network;

        /// <summary>
        /// Najlepsza osiagnieta siec
        /// </summary>
        ///
        private double[] najlepszaSiec;

        public WzrostBleduWalidacyjnegoStrategia(float maxWzrostBleduWalidacyjnego, bool przywrocSiec)
            : base(maxWzrostBleduWalidacyjnego, przywrocSiec) { }

        protected override double WyliczObecnyBladValidacyjny()
        {
            if (daneWalidacyjne != null && daneWalidacyjne.Length > 0 && daneWalidacyjne[0].Length > 0)
                return base.WyliczObecnyBladValidacyjny();
            else
                return this.train.Error;
        }

        public override void PrzywrocNajlepszaSiec()
        {
            this.network.DecodeFromArray(this.najlepszaSiec);
            Monitor.Instancja.NumerIteracji = this.numerIteracjiMinBlad;
            Monitor.Instancja.BladSieci = this.minBladTestowy;
        }

        #region IEndTrainingStrategy Members

        public bool ShouldStop()
        {
            return shouldStop;
        }

        #endregion

        #region IStrategy Members

        public void Init(IMLTrain train)
        {
            if (!(train.Method is IMLEncodable))
            {
                Monitor.Instancja.Logger.SendError("[EndValidationErrorIncrease Init] : Aby uzywac tej strategii nalezy korzystac z Sieci ktora jest IMLEncodable");
                throw new Exception("[EndValidationErrorIncrease Init] : Aby uzywac tej strategii nalezy korzystac z Sieci ktora jest IMLEncodable");
            }
            this.network = ((BasicNetwork)train.Method);
            this.train = train;
            this.shouldStop = false;
            this.minBladTestowy = this.minBlad = Double.MaxValue;
            this.numerIteracjiMinBlad = train.IterationNumber;
            this.najlepszaSiec = new double[this.network.EncodedArrayLength()];
            this.network.EncodeToArray(this.najlepszaSiec);
        }

        public void PostIteration()
        {
            if (train.IterationNumber > 50)
            {
                double obecnyBlad = WyliczObecnyBladValidacyjny();
                if (obecnyBlad > this.maxWzrostBleduWalidacyjnego * this.minBlad)
                {
                    shouldStop = true;
                    if (przywrocSiec)
                        this.PrzywrocNajlepszaSiec();
                    return;
                }
                if (obecnyBlad < this.minBlad) //-Monitor.Instancja.WarunekStopBleduSieci)
                {
                    this.minBlad = obecnyBlad;
                    this.minBladTestowy = this.train.Error;
                    this.numerIteracjiMinBlad = this.train.IterationNumber;
                    this.network.EncodeToArray(this.najlepszaSiec);
                }
            }
        }

        public void PreIteration()
        {
        }

        #endregion
    }


}
